from selenium.common.exceptions import NoSuchElementException
from appium.webdriver.common.touch_action import TouchAction
from appium.webdriver.common.multi_action import MultiAction
from init.init import start_app
from selenium.webdriver.common.by import By
from log.log import Logger
from time import sleep
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header

from openpyxl import load_workbook
import openpyxl
import yaml
from appium import webdriver
class App():
    def __init__(self):
        self.driver = None

    def start_app(self):
        with open('./init/init_conf_txty.yaml', 'r', encoding='utf-8') as f:
            yaml_data = yaml.load(f, Loader=yaml.FullLoader)  # 或者yaml.full_load()
        cas = {}
        cas['platformName'] = yaml_data['platformName']
        cas['platformVersion'] = yaml_data['platformVersion']
        cas['deviceName'] = yaml_data['deviceName']
        # cas['app'] = yaml_data['app']
        cas['appPackage'] = yaml_data['appPackage']
        cas['appActivity'] = yaml_data['appActivity']
        cas['noReset'] = yaml_data['noReset']
        cas['unicodeKeyboard'] = yaml_data['unicodeKeyboard']
        cas['resetKeyboard'] = yaml_data['resetKeyboard']
        self.driver = webdriver.Remote('http://' + str(yaml_data["ip"]) + ':' + str(yaml_data["port"]) + '/wd/hub', cas)
        self.driver.implicitly_wait(10)
        return self.driver

    # def loc(self, loc_type, value):
    #     # v1.0
    #     # if loc_type is 'xpath':
    #     #     return self.driver.find_element_by_xpath(value)
    #     # elif loc_type is 'id':
    #     #     return self.driver.find_element_by_id(value)
    #     try:
    #         return self.driver.find_element(getattr(By,loc_type.upper()),value)
    #     except Exception as e:
    #         Logger().log().info("定位元素出现异常，异常信息：\n{}".format(e))
    def findEle(self, loc=''):
        try:
            ele = None
            self.ele = None
            if loc.startswith('xpath='):
                ele = self.driver.find_element_by_xpath(loc[loc.find('=')+1:])
            elif loc.startswith('id='):
                print('进入id')
                ele = self.driver.find_element_by_id(loc[loc.find('=')+1:])

            elif loc.startswith('name='):
                ele = self.driver.find_element_by_name(loc[loc.find('=')+1:])
            elif loc.startswith('tag_name='):
                ele = self.driver.find_element_by_tag_name(loc[loc.find('=')+1:])
            elif loc.startswith('link_text='):
                ele = self.driver.find_element_by_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('partial_link_text='):
                ele = self.driver.find_element_by_partial_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('css_seletor='):
                ele = self.driver.find_element_by_css_seletor(loc[loc.find('=')+1:])
            else:
                ele = self.driver.find_element_by_xpath(loc)
            #运行web时才能使用
            # self.driver.execute_script("arguments[0].style.background='#ff3bff'", ele)
            self.ele = ele
            print('出来id')
            return ele
        except Exception as e:
            print('-----打印错误日志：{}'.format(e))

    # def input(self,loc_type,value,txt):
    #     self.loc(loc_type,value).send_keys(txt)

    def input(self, loc=None, value=None):
        print('进入input')
        ele = self.findEle(loc)
        ele.send_keys(str(value))
        print('出来input')

    # def click(self,loc_type,value):
    #     self.loc(loc_type,value).click()

    def click(self, loc = None):
        print('进入click')
        ele = self.findEle(loc)
        ele.click()
        print('出来click')

    def quit(self):
        self.driver.quit()# 这句一定要加，不加再次启动appium会无法创建一个新的sessionid

    # def sleep(self, time):
    #     time = int(time)
    #     sleep(time)

    def sleep(self, value=None):
        sleep(int(value))

    def tap(self, positions, duration):
        # 解决不同手机不同屏幕尺寸按键不同方法：https://blog.csdn.net/px551/article/details/104731406?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-1-104731406.pc_agg_new_rank&utm_term=python+tap%E6%96%B9%E6%B3%95&spm=1000.2123.3001.4430
        '''
        :param positions: list类型，里面对象是元组，最多五个。如：[(100, 20), (100, 60)]
        :param duration: 持续时间，单位毫秒，如：500
        :return:None
        '''
        positions = eval(positions)
        duration = int(duration)
        self.driver.tap(positions, duration)


    def cance(self, loc):
        Logger().log().info("检查是否有取消按钮")
        try:
            cance = self.findEle(loc)
        except NoSuchElementException:
            Logger().log().info("没有取消按钮")
        else:
            Logger().log().info("点击取消按钮")
            cance.click()

    def skip(self,  loc):
        Logger().log().info("检查是否有跳过按钮")
        try:
            skip = self.findEle(loc)
        except NoSuchElementException:
            Logger().log().info("没有跳过按钮")
        else:
            skip.click()
            Logger().log().info("点击跳过按钮")

    # 去掉不必要的弹窗
    def skips(self,  loc):
        Logger().log().info("检查是否有需要跳过的弹窗")
        try:
            skip = self.findEle(loc)
            skip.click()
            Logger().log().info("点击需要跳过的弹窗")
        except Exception as e:# 不同的异常方法也会有所不同
            Logger().log().info("没有需要跳过的弹窗")


    # 获取屏幕尺寸
    def size(self):
        x = self.driver.get_window_size()['width']
        y = self.driver.get_window_size()['height']
        return x, y
    # 自定义滑动
    def swipe(self, x1, y1, x2, y2):
        # 坐标滑动不稳定，推荐如下
        # self.driver.scroll(el1, el2)  # 从一个元素滑到另一个元素 稳定，推荐这个
        # TouchAction(self.driver).press(el1).move_to(el2).release().perform()  # 从一个元素滑到另一个元素
        '''

        :param x1: 起始点x
        :param y1: 起始点y
        :param x2: 结束点x
        :param y2: 结束点y
        :return:
        '''
        size = self.size()
        x1 = int(size[0]*x1)
        y1 = int(size[1]*y1)
        x2 = int(size[0]*x2)
        y2 = int(size[1]*y2)
        self.driver.swipe(x1, y1, x2, y2, 1000)
    # 左滑
    def left_swipe(self):
        size = self.size()
        x1 = int(size[0]*0.9)
        x2 = int(size[0]*0.1)
        y = int(size[1]*0.5)
        self.driver.swipe(x1, y, x2, y, 1000)

    # 右滑
    def right_swipe(self):
        size = self.size()
        x1 = int(size[0]*0.1)
        x2 = int(size[0]*0.9)
        y = int(size[1]*0.5)
        self.driver.swipe(x1, y, x2, y, 1000)

    def up_swipe(self):
        size = self.size()
        x = int(size[0]*0.5)
        y1 = int(size[1]*0.9)
        y2 = int(size[1]*0.1)
        self.driver.swipe(x, y1, x, y2, 1000)

    def down_swipe(self):
        size = self.size()
        x = int(size[0]*0.5)
        y1 = int(size[1]*0.1)
        y2 = int(size[1]*0.9)
        self.driver.swipe(x, y1, x, y2, 1000)

    #连续滑动解锁
    def slide_unlock(self):
        # 这是连续坐标滑动，也可以连续元素滑动
        # TouchAction().press(el1).move_to(el2).move_to(el3).move_to(el4).release().perform()  # 连续元素滑动
        TouchAction(self.driver)\
            .press(x=246, y=376).wait(2000) \
            .move_to(x=451, y=385).wait(1000) \
            .move_to(x=644, y=584).wait(1000) \
            .move_to(x=661, y=774).wait(1000) \
            .release().perform()

    # 根据屏幕大小上下左右滑动(上面已有)
    def slide_windows(self):
        # 获取元素的大小（高和宽）,按照屏幕分辨率来滑动
        x = self.driver.get_window_size()['width']
        y = self.driver.get_window_size()['height']
        self.driver.swipe(x * 0.5, y * 0.75, x * 0.5, y * 0.25, 500)  # 上滑
        self.driver.swipe(x * 0.5, y * 0.25, x * 0.5, y * 0.75, 500)  # 下滑
        self.driver.swipe(x * 0.75, y * 0.5, x * 0.25, y * 0.5, 500)  # 左滑
        self.driver.swipe(x * 0.25, y * 0.5, x * 0.75, y * 0.5, 500)  # 右滑

    def test_pull_file(self):
        """设备推送文件"""

        # 从设备中拉出文件 (Pull File)
        self.driver.pull_file('Library/AddressBook/AddressBook.sqlitedb')
        # 推送文件到设备中去
        data = "push test"
        path = "/data/local/tmp/file.txt"
        self.driver.push_file(path, data.encode('base64'))

        # self.driver.push_file(path, data.encode('base64', 'errors'))
        # self.driver.push_file(path, base64.b64encode(bytes("push test", 'utf-8')))

    def test_system(self):
        """系统杂项功能"""

        self.driver.app_strings(language=None, string_file=None)  # 获取应用字符串
        self.driver.background_app(5)  # 把当前应用置于后台5秒
        self.driver.hide_keyboard()  # 隐藏键盘
        self.driver.keyevent(176)  # 按键事件 (Key Event)给设备发送一个按键事件
        self.driver.toggle_location_services()  # 打开安卓设备上的位置定位设置
        # 打开一个应用或者activity，仅安卓端(百度糯米的包和activity名)
        self.driver.start_activity('com.nuomi', 'com.baidu.bainuo.dex.InstallDexActivity')

    def test_lock_and_open_notifaication(self):
        """锁屏和打开通知栏"""

        self.driver.open_notifications()  # 打开通知栏
        self.driver.find_element_by_id("com.android.systemui:id/clear_all_button").click()  # 点击清除通知
        self.driver.lock(5)  # 锁屏5秒

    def test_remove_install_reset(self):
        """卸载和安装app"""

        self.driver.is_app_installed("com.wochacha")  # 是否安装了app
        self.driver.remove_app("com.wochacha")  # 删除应用
        self.driver.install_app("D:/wochacha.apk")  # 安装应用
        self.driver.reset()  # 重置应用

    def test_launch_close_shake(self):
        """启动和关闭app,摇晃app"""

        # 这三个方法都报错，虽然不常用
        self.driver.launch_app()  # 启动应用
        self.driver.close_app()  # 关闭应用
        self.driver.shake()  # 摇晃设备

    # 缩放
    def zoom(self, x1, y1, x2, y2, a1, b1, a2, b2):
        size = self.driver.size()
        action1 = TouchAction(self.driver)
        action2 = TouchAction(self.driver)
        zoom_action = MultiAction(self.driver)
        action1.press(x=size[0] * x1, y=size[1] * y1).wait(1000).move_to(x=size[0] * x2, y=size[1] * y2).wait(1000).release()
        action2.press(x=size[0] * a1, y=size[1] * b1).wait(1000).move_to(x=size[0] * a2, y=size[1] * b2).wait(1000).release()

        zoom_action.add(action1, action2)
        zoom_action.perform()

    # 长按，appium2.0之前可能会失效
    def long_press(self, ele):
        TouchAction(self.driver).long_press(ele).perform()

    # 原生切换到h5
    def switch_to_h5(self):
        '''
        环境配置
        1.将下载符合版本的驱动（chrome://inspec可以看到哪个版本）放到路径下（原来的驱动用文件夹保存起来，如果是命令行appium运行，则路径不一样）
        2.将驱动放到d盘（d盘建一个目录存放，不确定放旧驱动还是新的，这一步可以不用）
        :return:
        '''
        contents = self.driver.contexts
        print("查看所有窗口/上下文", contents)
        self.driver.switch_to.context('WEBVIEW_com.wondershare.drfone')
        print("已切换到网页")
        # self.driver.find_element_by_id('email').send_keys('123...')

    # 原生切换到h5
    def switch_to_app(self):
        self.driver.switch_to.context('NATIVE_APP')
        print('从原生切回app了')
